package com.warrior.superdata.util;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.warrior.superdata.annotation.MysqlCheckInject;
import com.warrior.superdata.constants.ResultCode;
import com.warrior.superdata.exceptionhandler.ApplicationException;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Description:
 * @ClassName: com.warrior.wisdom.machine.room.util.MysqlCheckUtil.java
 * @date: 2021/12/28 16:32
 * @author xujian
 */
@Slf4j
public class MysqlCheckUtil {

    private final static String COLON = ":";

    private final static String METHOD_ADD = "add";

    private final static String METHOD_UPDATE = "update";

    private final static String PRIMARY_KEY = "id";

    private static List<Field> getAllFields(Object obj) {
        List<Field> fieldList = new ArrayList<>();
        Class<?> className = obj.getClass();
        for (; className != Object.class; className = className.getSuperclass()) {//获取自己和父级对象
            Field[] fields = className.getDeclaredFields();//获取全部私有字段
            for (Field field : fields) {
                field.setAccessible(true);
                fieldList.add(field);
            }
        }
        return fieldList;
    }

    public static void check(Object obj, String method) throws ApplicationException {
        Class<?> aClass = obj.getClass();
        QueryWrapper<Object> queryWrapper = new QueryWrapper<>();
        List<Field> fields = getAllFields(obj);
        Set uniqueFields = new HashSet<>();
        Map<String, Object> conditionUniqueValues = new HashMap<>();
        for (Field filed : fields) {
            try {
                filed.setAccessible(true);
                MysqlCheckInject fieldAnnotation = filed.getAnnotation(MysqlCheckInject.class);
                ApiModelProperty apiModelProperty = filed.getAnnotation(ApiModelProperty.class);
                if (null != fieldAnnotation) {
                    String uniqueField = fieldAnnotation.uniqueField();
                    String[] conditionUniqueFields = fieldAnnotation.conditionUniqueField();
                    if (null != conditionUniqueFields) {
                        for (String conditionUniqueField : conditionUniqueFields) {
                            Object value = BeanUtils.invokeGetMethod(obj, lineToHump(conditionUniqueField), null);
                            if (null != value) {
                                conditionUniqueValues.put(conditionUniqueField, value);
                            }
                        }
                    }
                    Object value = BeanUtils.invokeGetMethod(obj, filed.getName(), null);
                    if (StringUtils.isNotEmpty(uniqueField)) {
                        uniqueFields.add(apiModelProperty.value() + COLON + value);
                        queryWrapper.or().eq(uniqueField, value);
                    }
                }
            } catch (Exception e) {
                log.error("【sql组装异常 msg:{}】", e.getMessage());
            }
        }

        if (conditionUniqueValues.size() > 0) {
            queryWrapper.or(wrapper -> {
                conditionUniqueValues.keySet().forEach(key -> {
                    wrapper.eq(key, conditionUniqueValues.get(key));
                });
            });
        }
        MysqlCheckInject annotation = aClass.getAnnotation(MysqlCheckInject.class);
        Class mapper = annotation.mapper();
        BaseMapper bean = (BaseMapper) SpringUtil.getBean(mapper);
        List list = bean.selectList(queryWrapper);

        //新增参数验证
        if (METHOD_ADD.equals(method)) {
            if (!CollectionUtils.isEmpty(uniqueFields) && !CollectionUtils.isEmpty(list)) {
                throw new ApplicationException(ResultCode.FAIL_CODE, uniqueFields + "或" + conditionUniqueValues + "不能重复");
            }
        }

        //编辑参数验证
        if (METHOD_UPDATE.equals(method)) {
            if (!CollectionUtils.isEmpty(list) && list.size() > 1) {
                throw new ApplicationException(ResultCode.FAIL_CODE, uniqueFields + "或" + conditionUniqueValues + "不能重复");
            } else if (!CollectionUtils.isEmpty(list) && list.size() == 1) {
                Object o = list.get(0);
                //比较id
                Object id = BeanUtils.invokeGetMethod(o, PRIMARY_KEY, null);
                Object paramsId = BeanUtils.invokeGetMethod(obj, PRIMARY_KEY, null);
                if (!ObjectUtil.equals(id, paramsId)) {
                    throw new ApplicationException(ResultCode.FAIL_CODE, uniqueFields + "不能重复");
                }
            }
        }
    }

    private static final Pattern linePattern = Pattern.compile("_(\\w)");

    /** 下划线转驼峰 */
    public static String lineToHump(String str) {
        str = str.toLowerCase();
        Matcher matcher = linePattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

}
